//--------------------------------------------------------------------------------------
// File: CustomUI.cpp
//
// Sample to show usage of DXUT's GUI system
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//--------------------------------------------------------------------------------------
#include "StdAfx.h"
#include "DXUT.h"
#include "DXUTgui.h"
#include "DXUTguiIME.h"
#include "DXUTcamera.h"
#include "DXUTsettingsdlg.h"
#include "SDKmesh.h"
#include "SDKmisc.h"
#include "Mesh.h"
#include "Hausdorff.h"
#include "guicon.h"
#include "HausdorffSolver.h"

#define GUI_CONSOLE
//--------------------------------------------------------------------------------------
// Global variables
//--------------------------------------------------------------------------------------
ID3DXFont*                  g_pFont = NULL;         // Font for drawing text
ID3DXSprite*                g_pTextSprite = NULL;   // Sprite for batching draw text calls
D3DXMATRIXA16               g_mView;
CModelViewerCamera          g_Camera;               // A model viewing camera
CDXUTDialogResourceManager  g_DialogResourceManager; // manager for shared resources of dialogs
CD3DSettingsDlg             g_SettingsDlg;          // Device settings dialog
CDXUTDialog                 g_HUD;                  // dialog for standard controls
CDXUTDialog                 g_SampleUI;             // dialog for sample specific controls

CMesh*						g_pMesh1 = NULL;
CMesh*						g_pMesh2 = NULL;
D3DXVECTOR3					g_vMesh2Offset;

CHausdorffSolver*			g_pSolver = NULL;

//--------------------------------------------------------------------------------------
// UI control IDs
//--------------------------------------------------------------------------------------
enum UI_CONTROL_ID
{
	IDC_TOGGLEFULLSCREEN = 1,
	IDC_TOGGLEREF,
	IDC_CHANGEDEVICE,
	IDC_COMPUTEHAUSDORFF,
	IDC_LISTBOX1,
	IDC_LISTBOX2,
	IDC_SLIDER,
	IDC_SLIDER_MESH2_X,
	IDC_SLIDER_MESH2_Y,
	IDC_SLIDER_MESH2_Z,
	IDC_CHECKBOX,
	IDC_OUTPUT,
};

//--------------------------------------------------------------------------------------
// Forward declarations 
//--------------------------------------------------------------------------------------
bool CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat, bool bWindowed,
	void* pUserContext );
bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, void* pUserContext );
HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
	void* pUserContext );
HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
	void* pUserContext );
void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void* pUserContext );
void CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext );
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing,
	void* pUserContext );
void CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown, void* pUserContext );
void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl, void* pUserContext );
void CALLBACK OnLostDevice( void* pUserContext );
void CALLBACK OnDestroyDevice( void* pUserContext );

void InitApp();
void RenderText();

//--------------------------------------------------------------------------------------
// Entry point to the program. Initializes everything and goes into a message processing 
// loop. Idle time is used to render the scene.
//--------------------------------------------------------------------------------------
INT WINAPI wWinMain( HINSTANCE, HINSTANCE, LPWSTR, int )
{
#if defined(DEBUG) | defined(_DEBUG)
	// Enable run-time memory check for debug builds.
	_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif

#if defined(GUI_CONSOLE)
	// make a console window
	RedirectIOToConsole(); 
#endif

	g_pSolver = new CHausdorffSolver;

	// DXUT will create and use the best device (either D3D9 or D3D10) 
	// that is available on the system depending on which D3D callbacks are set below

	// Set DXUT callbacks
	DXUTSetCallbackD3D9DeviceAcceptable( IsDeviceAcceptable );
	DXUTSetCallbackD3D9DeviceCreated( OnCreateDevice );
	DXUTSetCallbackD3D9DeviceReset( OnResetDevice );
	DXUTSetCallbackD3D9FrameRender( OnFrameRender );
	DXUTSetCallbackD3D9DeviceLost( OnLostDevice );
	DXUTSetCallbackD3D9DeviceDestroyed( OnDestroyDevice );
	DXUTSetCallbackMsgProc( MsgProc );
	DXUTSetCallbackKeyboard( KeyboardProc );
	DXUTSetCallbackFrameMove( OnFrameMove );
	DXUTSetCallbackDeviceChanging( ModifyDeviceSettings );

	DXUTSetCursorSettings( true, true );
	InitApp();
	DXUTInit( true, true ); // Parse the command line and show msgboxes
	DXUTSetHotkeyHandling( true, true, true );
	DXUTCreateWindow( L"CustomUI" );
	DXUTCreateDevice( true, 640, 480 );
	DXUTMainLoop();

	delete g_pSolver;

	return DXUTGetExitCode();
}


//--------------------------------------------------------------------------------------
// Initialize the app 
//--------------------------------------------------------------------------------------
void InitApp()
{
	// Initialize dialogs
	g_SettingsDlg.Init( &g_DialogResourceManager );
	g_HUD.Init( &g_DialogResourceManager );
	g_SampleUI.Init( &g_DialogResourceManager );

	g_HUD.SetCallback( OnGUIEvent ); int iY = 10;
	g_HUD.AddButton( IDC_TOGGLEFULLSCREEN, L"Toggle full screen", 35, iY, 125, 22 );
	g_HUD.AddButton( IDC_TOGGLEREF, L"Toggle REF (F3)", 35, iY += 24, 125, 22 );
	g_HUD.AddButton( IDC_CHANGEDEVICE, L"Change device (F2)", 35, iY += 24, 125, 22, VK_F2 );

	g_SampleUI.SetCallback( OnGUIEvent );

	g_SampleUI.SetFont( 1, L"Comic Sans MS", 24, FW_NORMAL );
	g_SampleUI.SetFont( 2, L"Courier New", 16, FW_NORMAL );

	// Static
	g_SampleUI.AddStatic( IDC_OUTPUT,
		L"This static control provides feedback for your action.  It will change as you interact with the UI controls.", 20, 50, 620, 300 );
	g_SampleUI.GetStatic( IDC_OUTPUT )->SetTextColor( D3DCOLOR_ARGB( 255, 255, 0, 0 ) ); // Change color to red
	g_SampleUI.GetControl( IDC_OUTPUT )->GetElement( 0 )->dwTextFormat = DT_LEFT | DT_TOP | DT_WORDBREAK;
	g_SampleUI.GetControl( IDC_OUTPUT )->GetElement( 0 )->iFont = 2;

	// Buttons
	g_SampleUI.AddButton( IDC_COMPUTEHAUSDORFF, L"Compute (H)ausdorff", 30, 430, 180, 35, L'H' );

	// Slider
	g_SampleUI.AddSlider( IDC_SLIDER, 200, 450, 200, 24, 0, MAX_TREE_LEVEL, 0, false );

	g_SampleUI.AddSlider( IDC_SLIDER_MESH2_X, 200, 450, 190, 24, -100, 100, 0, false );
	g_SampleUI.AddSlider( IDC_SLIDER_MESH2_Y, 200, 450, 190, 24, -100, 100, 0, false );
	g_SampleUI.AddSlider( IDC_SLIDER_MESH2_Z, 200, 450, 190, 24, -100, 100, 0, false );

	// Checkbox
	g_SampleUI.AddCheckBox( IDC_CHECKBOX, L"(S)how Sphere Tree",
		170, 450, 350, 24, false, L'S', false );

	// List box
	g_SampleUI.AddListBox( IDC_LISTBOX1, 30, 400, 200, 150, 0 );
	g_SampleUI.GetListBox( IDC_LISTBOX1 )->AddItem( L"None", ( LPVOID )( size_t )0 );
	g_SampleUI.GetListBox( IDC_LISTBOX1 )->AddItem( L"bun_zipper_res4.ply", ( LPVOID )( size_t )1 );
	g_SampleUI.GetListBox( IDC_LISTBOX1 )->AddItem( L"bun_zipper_res3.ply", ( LPVOID )( size_t )2 );
	g_SampleUI.GetListBox( IDC_LISTBOX1 )->AddItem( L"bun_zipper_res2.ply", ( LPVOID )( size_t )3 );
	g_SampleUI.GetListBox( IDC_LISTBOX1 )->AddItem( L"bun_zipper.ply", ( LPVOID )( size_t )4 );
	g_SampleUI.GetListBox( IDC_LISTBOX1 )->AddItem( L"dragon_vrip_res4.ply", ( LPVOID )( size_t )5 );
	g_SampleUI.GetListBox( IDC_LISTBOX1 )->AddItem( L"dragon_vrip_res3.ply", ( LPVOID )( size_t )6 );
	g_SampleUI.GetListBox( IDC_LISTBOX1 )->AddItem( L"dragon_vrip_res2.ply", ( LPVOID )( size_t )7 );

	g_SampleUI.AddListBox( IDC_LISTBOX2, 30, 400, 200, 150, 0 );
	g_SampleUI.GetListBox( IDC_LISTBOX2 )->AddItem( L"None", ( LPVOID )( size_t )0 );
	g_SampleUI.GetListBox( IDC_LISTBOX2 )->AddItem( L"bun_zipper_res4.ply", ( LPVOID )( size_t )1 );
	g_SampleUI.GetListBox( IDC_LISTBOX2 )->AddItem( L"bun_zipper_res3.ply", ( LPVOID )( size_t )2 );
	g_SampleUI.GetListBox( IDC_LISTBOX2 )->AddItem( L"bun_zipper_res2.ply", ( LPVOID )( size_t )3 );
	g_SampleUI.GetListBox( IDC_LISTBOX2 )->AddItem( L"bun_zipper.ply", ( LPVOID )( size_t )4 );
	g_SampleUI.GetListBox( IDC_LISTBOX2 )->AddItem( L"dragon_vrip_res4.ply", ( LPVOID )( size_t )5 );
	g_SampleUI.GetListBox( IDC_LISTBOX2 )->AddItem( L"dragon_vrip_res3.ply", ( LPVOID )( size_t )6 );
	g_SampleUI.GetListBox( IDC_LISTBOX2 )->AddItem( L"dragon_vrip_res2.ply", ( LPVOID )( size_t )7 );
}


//--------------------------------------------------------------------------------------
// Rejects any D3D9 devices that aren't acceptable to the app by returning false
//--------------------------------------------------------------------------------------
bool CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat,
	D3DFORMAT BackBufferFormat, bool bWindowed, void* pUserContext )
{
	// Skip backbuffer formats that don't support alpha blending
	IDirect3D9* pD3D = DXUTGetD3D9Object();
	if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType,
		AdapterFormat, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING,
		D3DRTYPE_TEXTURE, BackBufferFormat ) ) )
		return false;

	// Must support pixel shader 2.0
	if( pCaps->PixelShaderVersion < D3DPS_VERSION( 2, 0 ) )
		return false;

	return true;
}


//--------------------------------------------------------------------------------------
// Called right before creating a D3D9 or D3D10 device, allowing the app to modify the device settings as needed
//--------------------------------------------------------------------------------------
bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, void* pUserContext )
{
	assert( DXUT_D3D9_DEVICE == pDeviceSettings->ver );

	HRESULT hr;
	IDirect3D9* pD3D = DXUTGetD3D9Object();
	D3DCAPS9 caps;

	V( pD3D->GetDeviceCaps( pDeviceSettings->d3d9.AdapterOrdinal,
		pDeviceSettings->d3d9.DeviceType,
		&caps ) );

	// If device doesn't support HW T&L or doesn't support 1.1 vertex shaders in HW 
	// then switch to SWVP.
	if( ( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT ) == 0 ||
		caps.VertexShaderVersion < D3DVS_VERSION( 1, 1 ) )
	{
		pDeviceSettings->d3d9.BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
	}

	// For the first device created if its a REF device, optionally display a warning dialog box
	static bool s_bFirstTime = true;
	if( s_bFirstTime )
	{
		s_bFirstTime = false;
		if( pDeviceSettings->d3d9.DeviceType == D3DDEVTYPE_REF )
			DXUTDisplaySwitchingToREFWarning( pDeviceSettings->ver );
	}

	return true;
}


//--------------------------------------------------------------------------------------
// Create any D3D9 resources that will live through a device reset (D3DPOOL_MANAGED)
// and aren't tied to the back buffer size
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
	void* pUserContext )
{
	HRESULT hr;

	CDXUTIMEEditBox::Initialize( DXUTGetHWND() );

	V_RETURN( g_DialogResourceManager.OnD3D9CreateDevice( pd3dDevice ) );
	V_RETURN( g_SettingsDlg.OnD3D9CreateDevice( pd3dDevice ) );
	// Initialize the font
	V_RETURN( D3DXCreateFont( pd3dDevice, 15, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET,
		OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE,
		L"Arial", &g_pFont ) );

	// Setup the camera's view parameters
	D3DXVECTOR3 vecEye( 0.0f, 0.1f, -0.5f );
	D3DXVECTOR3 vecAt ( 0.0f, 0.1f, 0.0f );
	D3DXVECTOR3 vecUp ( 0.0f, 1.0f, 0.0f );
	g_Camera.SetViewParams( &vecEye, &vecAt );
	D3DXMatrixLookAtLH( &g_mView, &vecEye, &vecAt, &vecUp );

	g_pSolver->InitD3DBuffer();

	return S_OK;
}

//--------------------------------------------------------------------------------------
// Create any D3D9 resources that won't live through a device reset (D3DPOOL_DEFAULT) 
// or that are tied to the back buffer size 
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice,
	const D3DSURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext )
{
	HRESULT hr;

	V_RETURN( g_DialogResourceManager.OnD3D9ResetDevice() );
	V_RETURN( g_SettingsDlg.OnD3D9ResetDevice() );

	if( g_pFont )
		V_RETURN( g_pFont->OnResetDevice() );

	// Create a sprite to help batch calls when drawing many lines of text
	V_RETURN( D3DXCreateSprite( pd3dDevice, &g_pTextSprite ) );

	// Setup the camera's projection parameters
	float fAspectRatio = pBackBufferSurfaceDesc->Width / ( FLOAT )pBackBufferSurfaceDesc->Height;
	g_Camera.SetProjParams( D3DX_PI / 4, fAspectRatio, 0.1f, 1000.0f );
	g_Camera.SetWindow( pBackBufferSurfaceDesc->Width, pBackBufferSurfaceDesc->Height );

	g_HUD.SetLocation( pBackBufferSurfaceDesc->Width - 170, 0 );
	g_HUD.SetSize( 170, 170 );
	g_SampleUI.SetLocation( 0, 0 );
	g_SampleUI.SetSize( pBackBufferSurfaceDesc->Width, pBackBufferSurfaceDesc->Height );

	g_SampleUI.GetControl( IDC_OUTPUT )->SetSize( pBackBufferSurfaceDesc->Width - 170, pBackBufferSurfaceDesc->Height /
		4 );
	g_SampleUI.GetControl( IDC_CHECKBOX )->SetLocation( 10, pBackBufferSurfaceDesc->Height - 180 );
	g_SampleUI.GetControl( IDC_SLIDER )->SetLocation( 10, pBackBufferSurfaceDesc->Height - 140 );
	g_SampleUI.GetControl( IDC_COMPUTEHAUSDORFF )->SetLocation( 10, pBackBufferSurfaceDesc->Height - 60 );
	
	g_SampleUI.GetControl( IDC_LISTBOX1 )->SetLocation( pBackBufferSurfaceDesc->Width - 400,
		pBackBufferSurfaceDesc->Height - 180 );
	g_SampleUI.GetControl( IDC_LISTBOX1 )->SetSize( 190, 96 );
	g_SampleUI.GetControl( IDC_LISTBOX2 )->SetLocation( pBackBufferSurfaceDesc->Width - 200,
		pBackBufferSurfaceDesc->Height - 180 );
	g_SampleUI.GetControl( IDC_LISTBOX2 )->SetSize( 190, 96 );

	g_SampleUI.GetControl( IDC_SLIDER_MESH2_X )->SetLocation( pBackBufferSurfaceDesc->Width - 200, pBackBufferSurfaceDesc->Height - 80 );
	g_SampleUI.GetControl( IDC_SLIDER_MESH2_Y )->SetLocation( pBackBufferSurfaceDesc->Width - 200, pBackBufferSurfaceDesc->Height - 55 );
	g_SampleUI.GetControl( IDC_SLIDER_MESH2_Z )->SetLocation( pBackBufferSurfaceDesc->Width - 200, pBackBufferSurfaceDesc->Height - 30 );

	if (g_pMesh1)
		g_pMesh1->OnResetDevice();
	if (g_pMesh2)
		g_pMesh2->OnResetDevice();

	g_pSolver->OnResetDevice();

	return S_OK;
}


//--------------------------------------------------------------------------------------
// Handle updates to the scene.  This is called regardless of which D3D API is used
//--------------------------------------------------------------------------------------
void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void* pUserContext )
{
	D3DXMATRIXA16 m;
	D3DXMatrixRotationY( &m, D3DX_PI * fElapsedTime / 40.0f );
	D3DXMatrixMultiply( &g_mView, &m, &g_mView );
}


//--------------------------------------------------------------------------------------
// Render the scene using the D3D9 device
//-------------------------------------------------------------------------------------- 
void CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
{
	if( g_SettingsDlg.IsActive() )
	{
		g_SettingsDlg.OnRender( fElapsedTime );
		return;
	}

	HRESULT hr;
	D3DXMATRIXA16 mWorld;
	D3DXMATRIXA16 mView;
	D3DXMATRIXA16 mProj;
	D3DXMATRIXA16 mWorldViewProjection;

	// Clear the render target and the zbuffer 
	V( pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB( 255, 128, 128, 255 ), 1.0f, 0 ) );

	// Render the scene
	if( SUCCEEDED( pd3dDevice->BeginScene() ) )
	{
		// Get the projection & view matrix from the camera class
		mWorld = *g_Camera.GetWorldMatrix();
		mProj = *g_Camera.GetProjMatrix();
		mView = g_mView;

		mWorldViewProjection = mWorld * mView * mProj;
		
		pd3dDevice->SetTransform( D3DTS_WORLD, &mWorld );
		pd3dDevice->SetTransform( D3DTS_VIEW, &mView );
		pd3dDevice->SetTransform( D3DTS_PROJECTION, &mProj );
		
		pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
		pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
		//pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_FLAT);

		BOOL bRenderSphere = g_SampleUI.GetCheckBox(IDC_CHECKBOX)->GetChecked();
		int iTreeLevel = g_SampleUI.GetSlider(IDC_SLIDER)->GetValue();
		if (g_pMesh1)
			g_pMesh1->Render(pd3dDevice, bRenderSphere, iTreeLevel);
		if (g_pMesh2)
			g_pMesh2->Render(pd3dDevice, bRenderSphere, iTreeLevel);

		if (g_pSolver)
			g_pSolver->RenderScene();

		RenderText();
		V( g_HUD.OnRender( fElapsedTime ) );
		V( g_SampleUI.OnRender( fElapsedTime ) );

		V( pd3dDevice->EndScene() );
	}
}


//--------------------------------------------------------------------------------------
// Render the help and statistics text. This function uses the ID3DXFont interface for 
// efficient text rendering.
//--------------------------------------------------------------------------------------
void RenderText()
{
	CDXUTTextHelper txtHelper( g_pFont, g_pTextSprite, 15 );

	// Output statistics
	txtHelper.Begin();
	txtHelper.SetInsertionPos( 5, 5 );
	txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 0.0f, 1.0f ) );
	txtHelper.DrawTextLine( DXUTGetFrameStats( DXUTIsVsyncEnabled() ) );
	txtHelper.DrawTextLine( DXUTGetDeviceStats() );
	txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) );
	txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) );
	txtHelper.DrawTextLine( L"Press ESC to quit" );
	txtHelper.End();
}


//--------------------------------------------------------------------------------------
// Handle messages to the application
//--------------------------------------------------------------------------------------
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing,
	void* pUserContext )
{
	// Always allow dialog resource manager calls to handle global messages
	// so GUI state is updated correctly
	*pbNoFurtherProcessing = CDXUTIMEEditBox::StaticMsgProc( hWnd, uMsg, wParam, lParam );
	if( *pbNoFurtherProcessing )
		return 0;
	*pbNoFurtherProcessing = g_DialogResourceManager.MsgProc( hWnd, uMsg, wParam, lParam );
	if( *pbNoFurtherProcessing )
		return 0;

	if( g_SettingsDlg.IsActive() )
	{
		g_SettingsDlg.MsgProc( hWnd, uMsg, wParam, lParam );
		return 0;
	}

	// Give the dialogs a chance to handle the message first
	*pbNoFurtherProcessing = g_HUD.MsgProc( hWnd, uMsg, wParam, lParam );
	if( *pbNoFurtherProcessing )
		return 0;
	*pbNoFurtherProcessing = g_SampleUI.MsgProc( hWnd, uMsg, wParam, lParam );
	if( *pbNoFurtherProcessing )
		return 0;

	// Pass all remaining windows messages to camera so it can respond to user input
	g_Camera.HandleMessages( hWnd, uMsg, wParam, lParam );

	return 0;
}


//--------------------------------------------------------------------------------------
// Handle key presses
//--------------------------------------------------------------------------------------
void CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown, void* pUserContext )
{
}


//--------------------------------------------------------------------------------------
// Handles the GUI events
//--------------------------------------------------------------------------------------
void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl, void* pUserContext )
{
	WCHAR wszOutput[1024];

	switch( nControlID )
	{
	case IDC_TOGGLEFULLSCREEN:
		DXUTToggleFullScreen(); break;
	case IDC_TOGGLEREF:
		DXUTToggleREF(); break;
	case IDC_CHANGEDEVICE:
		g_SettingsDlg.SetActive( !g_SettingsDlg.IsActive() ); break;
	case IDC_COMPUTEHAUSDORFF:
		g_SampleUI.GetStatic( IDC_OUTPUT )->SetText(
			L"You clicked the 'Compute Hausdorff' button.\nxxx" );

		if (g_pMesh2)
			g_pMesh2->FinalizeMesh();
		g_vMesh2Offset = D3DXVECTOR3(0, 0, 0);
		g_SampleUI.GetSlider(IDC_SLIDER_MESH2_X)->SetValue(0);
		g_SampleUI.GetSlider(IDC_SLIDER_MESH2_Y)->SetValue(0);
		g_SampleUI.GetSlider(IDC_SLIDER_MESH2_Z)->SetValue(0);

		g_pSolver->SetMesh(0, g_pMesh1);
		g_pSolver->SetMesh(1, g_pMesh2);
		g_pSolver->Solve();
		break;

	case IDC_SLIDER:
		{
			int iNodeCount1 = 0, iNodeCount2 = 0;
			if (g_pMesh1)
				iNodeCount1 = g_pMesh1->GetNodeCount( ( ( CDXUTSlider* )pControl )->GetValue() );
			if (g_pMesh2)
				iNodeCount2 = g_pMesh2->GetNodeCount( ( ( CDXUTSlider* )pControl )->GetValue() );
			swprintf_s( wszOutput, 1024, L"You adjusted the slider control.\nThe new value reported is %d\n# of Tree Nodes in Mesh1 : %d\n# of Tree Nodes in Mesh2 : %d",
				( ( CDXUTSlider* )pControl )->GetValue(), iNodeCount1, iNodeCount2 );
			g_SampleUI.GetStatic( IDC_OUTPUT )->SetText( wszOutput );
		}
		break;

	case IDC_SLIDER_MESH2_X:
	case IDC_SLIDER_MESH2_Y:
	case IDC_SLIDER_MESH2_Z:
		{
			g_vMesh2Offset.x = g_SampleUI.GetSlider(IDC_SLIDER_MESH2_X)->GetValue() / 100.f;
			g_vMesh2Offset.y = g_SampleUI.GetSlider(IDC_SLIDER_MESH2_Y)->GetValue() / 100.f;
			g_vMesh2Offset.z = g_SampleUI.GetSlider(IDC_SLIDER_MESH2_Z)->GetValue() / 100.f;

			swprintf_s( wszOutput, 1024, L"You adjusted the mesh2 offset.\nThe new offset is (%f, %f, %f)",
				g_vMesh2Offset.x, g_vMesh2Offset.y, g_vMesh2Offset.z );
			g_SampleUI.GetStatic( IDC_OUTPUT )->SetText( wszOutput );

			if (g_pMesh2)
				g_pMesh2->SetTranslation(g_vMesh2Offset);
		}
		break;

	case IDC_CHECKBOX:
		swprintf_s( wszOutput, 1024, L"You %s show sphere tree check box.",
			( ( CDXUTCheckBox* )pControl )->GetChecked() ? L"checked" : L"cleared" );
		g_SampleUI.GetStatic( IDC_OUTPUT )->SetText( wszOutput );
		break;
	case IDC_LISTBOX1:
		switch( nEvent )
		{
		case EVENT_LISTBOX_ITEM_DBLCLK:
			{
				DXUTListBoxItem* pItem = ( ( CDXUTListBox* )pControl )->GetItem(
					( ( CDXUTListBox* )pControl )->GetSelectedIndex( -1 ) );

				if (g_pMesh1)
					g_pMesh1->Destroy();
				delete g_pMesh1;
				g_pMesh1 = NULL;

				if ( ( ( CDXUTListBox* )pControl )->GetSelectedIndex( -1 ) > 0 && pItem)
				{	
					g_pMesh1 = new CMesh(D3DXCOLOR(1.f, 0.0f, 0.0f, 1.f));
					g_pMesh1->LoadFromFile(pItem->strText);
					g_pMesh1->BuildSphereTree();
					g_pMesh1->InitD3DBuffer(DXUTGetD3D9Device());
				}
				int iNumVert = 0, iNumTri = 0;
				if (g_pMesh1)
				{
					iNumVert = g_pMesh1->GetNumVertices();
					iNumTri = g_pMesh1->GetNumTriangles();
				}

				swprintf_s( wszOutput, 1024,
					L"You double clicked an item in the mesh1 list box.  The item is \"%s\"\n# of vertices : %d\n# of triangles : %d",
					pItem ? pItem->strText : L"", iNumVert, iNumTri );
				g_SampleUI.GetStatic( IDC_OUTPUT )->SetText( wszOutput );
				break;
			}

		case EVENT_LISTBOX_SELECTION:
			{
				swprintf_s( wszOutput, 1024,
					L"You changed the selection in the mesh1 list box.  The selected item is %d",
					( ( CDXUTListBox* )pControl )->GetSelectedIndex() );
				g_SampleUI.GetStatic( IDC_OUTPUT )->SetText( wszOutput );
				break;
			}
		}
		break;

	case IDC_LISTBOX2:
		switch( nEvent )
		{
		case EVENT_LISTBOX_ITEM_DBLCLK:
			{
				DXUTListBoxItem* pItem = ( ( CDXUTListBox* )pControl )->GetItem(
					( ( CDXUTListBox* )pControl )->GetSelectedIndex( -1 ) );

				if (g_pMesh2)
					g_pMesh2->Destroy();
				delete g_pMesh2;
				g_pMesh2 = NULL;

				if ( ( ( CDXUTListBox* )pControl )->GetSelectedIndex( -1 ) > 0 && pItem)
				{
					g_pMesh2 = new CMesh(D3DXCOLOR(0.0f, 1.f, 0.0f, 1.f));
					g_pMesh2->LoadFromFile(pItem->strText);
					g_pMesh2->BuildSphereTree();
					g_pMesh2->InitD3DBuffer(DXUTGetD3D9Device());

					g_pMesh2->SetTranslation(g_vMesh2Offset);
				}
				int iNumVert = 0, iNumTri = 0;
				if (g_pMesh2)
				{
					iNumVert = g_pMesh2->GetNumVertices();
					iNumTri = g_pMesh2->GetNumTriangles();
				}

				swprintf_s( wszOutput, 1024,
					L"You double clicked an item in the mesh2 list box.  The item is \"%s\"\n# of vertices : %d\n# of triangles : %d",
					pItem ? pItem->strText : L"", iNumVert, iNumTri );
				g_SampleUI.GetStatic( IDC_OUTPUT )->SetText( wszOutput );
				break;
			}

		case EVENT_LISTBOX_SELECTION:
			{
				swprintf_s( wszOutput, 1024,
					L"You changed the selection in the mesh2 list box.  The selected item is %d",
					( ( CDXUTListBox* )pControl )->GetSelectedIndex() );
				g_SampleUI.GetStatic( IDC_OUTPUT )->SetText( wszOutput );
				break;
			}
		}
		break;
	}
}


//--------------------------------------------------------------------------------------
// Release D3D9 resources created in the OnD3D9ResetDevice callback 
//--------------------------------------------------------------------------------------
void CALLBACK OnLostDevice( void* pUserContext )
{
	g_DialogResourceManager.OnD3D9LostDevice();
	g_SettingsDlg.OnD3D9LostDevice();

	if( g_pFont )
		g_pFont->OnLostDevice();

	SAFE_RELEASE( g_pTextSprite );

	if (g_pMesh1)
		g_pMesh1->OnLostDevice();
	if (g_pMesh2)
		g_pMesh2->OnLostDevice();

	g_pSolver->OnLostDevice();
}


//--------------------------------------------------------------------------------------
// Release D3D9 resources created in the OnD3D9CreateDevice callback 
//--------------------------------------------------------------------------------------
void CALLBACK OnDestroyDevice( void* pUserContext )
{
	CDXUTIMEEditBox::Uninitialize( );

	g_DialogResourceManager.OnD3D9DestroyDevice();
	g_SettingsDlg.OnD3D9DestroyDevice();

	if (g_pMesh1)
	{
		g_pMesh1->Destroy();
		delete g_pMesh1;
		g_pMesh1 = NULL;
	}
	if (g_pMesh2)
	{
		g_pMesh2->Destroy();
		delete g_pMesh2;
		g_pMesh2 = NULL;
	}

	g_pSolver->OnDestroy();

	SAFE_RELEASE( g_pFont );
}
